﻿using Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Device
{
    /// <summary>
    /// 万用表类
    /// </summary>
    public class DM3058E
    {
        static DM3058E()
        {
            //直流电压量程参数 单位：V
            SetRangeParam.Add(Function.DCV, new Dictionary<string, double>
            {
                {"0",0.2 }, {"1",2}, {"2",20}, {"3",200}, {"4",1000},
            });
            //交流电压量程参数 单位：V
            SetRangeParam.Add(Function.ACV, new Dictionary<string, double>
            {
                {"0",0.2 }, {"1",2}, {"2",20}, {"3",200}, {"4",750},
            });

            //直流电流量程参数 单位：A
            SetRangeParam.Add(Function.DCI, new Dictionary<string, double>
            {
                {"0",0.0002 }, {"1",0.002}, {"2",0.02}, {"3",0.2}, {"4",2},{"5",10}
            });

            // 交流电流量程参数 单位：A
            SetRangeParam.Add(Function.ACI, new Dictionary<string, double>
            {
                {"0",0.02 }, {"1",0.2}, {"2",2}, {"3",10}
            });

            //设置二线电阻测量量程 单位：Ω
            SetRangeParam.Add(Function.WR2, new Dictionary<string, double>
            {
                {"0",200 }, {"1",2000}, {"2",20000}, {"3",200000}, {"4",2000000},{"5",10000000},{"6",100000000}
            });

            //设置四线电阻测量量程 单位：Ω
            SetRangeParam.Add(Function.WR4, new Dictionary<string, double>
            {
                {"0",200 }, {"1",2000}, {"2",20000}, {"3",200000}, {"4",1000000},{"5",10000000},{"6",100000000}
            });

            // 设置频率测量时输入信号的电压量程 单位：V
            SetRangeParam.Add(Function.FREQ, new Dictionary<string, double>
            {
                {"0",0.2 }, {"1",2}, {"2",20}, {"3",200}, {"4",750},
            });

            // 设置周期测量时输入电压的量程 单位：V
            SetRangeParam.Add(Function.PERI, new Dictionary<string, double>
            {
                {"0",0.2 }, {"1",2}, {"2",20}, {"3",200}, {"4",750},
            });

            // 设置短路测量时的极限电阻值 单位：Ω 设置短路测量的极限电阻值为 1kΩ： //:MEASure: CONTinuity 1000
            SetRangeParam.Add(Function.CONT, new Dictionary<string, double>
            {
                {"MIN",1 }, {"MAX",2000}
            });

            // 设置电容测量量程 单位：微法，最大量程位10毫法
            SetRangeParam.Add(Function.CAP, new Dictionary<string, double>
            {
                {"0",0.002 }, {"1",0.02}, {"2",0.2}, {"3",2}, {"4",200},{"5",10000}
            });
        }

        /// <summary>
        /// 设置测试精度指令映射
        /// </summary>
        public static Dictionary<Function, Dictionary<string, double>> SetRangeParam = new Dictionary<Function, Dictionary<string, double>>();

        private static Dictionary<Function, string> SetRangeCmd = new Dictionary<Function, string>
            {
                {Function.DCV,":MEASure:VOLTage:DC" },
                {Function.ACV,":MEASure:VOLTage:AC" },
                {Function.DCI,":MEASure:CURRent:DC" },
                {Function.ACI,":MEASure:CURRent:AC" },
                {Function.WR2,":MEASure:RESistance" },
                {Function.WR4,":MEASure:FRESistance" },
                {Function.FREQ,":MEASure:FREQuency" },
                {Function.PERI,":MEASure:PERiod" },
                {Function.CONT,":MEASure:CONTinuity" },
                {Function.DIODE,":MEASure:DIODe" },
                {Function.CAP,":MEASure:CAPacitance" }
            };

        private static Dictionary<Function, string> SetFunctionCmd = new Dictionary<Function, string>
            {
                { Function.DCV,":FUNCtion:VOLTage:DC"},
                { Function.ACV,":FUNCtion:VOLTage:AC"},
                { Function.DCI,":FUNCtion:CURRent:DC"},
                { Function.ACI,":FUNCtion:CURRent:AC"},
                { Function.WR2,":FUNCtion:RESistance"},
                { Function.WR4,":FUNCtion:FRESistance"},
                { Function.FREQ,":FUNCtion:FREQuency"},
                { Function.PERI,":FUNCtion:PERiod"},
                { Function.CONT,":FUNCtion:CONTinuity"},
                { Function.DIODE,":FUNCtion:DIODe"},
                { Function.CAP,":FUNCtion:CAPacitance"}
            };

        private const string StopCode = "\r\n";
        private static bool connected = false;

        private static SerialPort serialPort;
        private static string deviceName = "万用表DM3058E";
        private static string recvData;
        private static ManualResetEventSlim manualResetEventSlim;

        /// <summary>
        /// 断开连接
        /// </summary>
        public static void Close()
        {
            serialPort?.Close();
            connected = false;
        }

        /// <summary>
        /// 串口连接
        /// </summary>
        /// <param name="port"> </param>
        /// <param name="baud"> </param>
        /// <exception cref="Exception"> </exception>
        [Conditional("DEVICE")]
        public static void Connect(string port, int baud = 9600)
        {
            if (connected) return;

            serialPort = new SerialPort();
            serialPort.BaudRate = baud;
            serialPort.PortName = port;

            ManualResetEventSlim openCompletedEvent = new ManualResetEventSlim(false);
            Task.Run(() =>
            {
                serialPort.Open();
                openCompletedEvent.Set();
            });
            if (!openCompletedEvent.Wait(2000))
            {
                throw new Exception($"DM3058E连接超时");
            }
            serialPort.DataReceived += SerialPort_DataReceived;
            //SendCmd(CmdOpenCurrentDC);
            connected = true;
        }

        private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            {
                recvData = null;
                recvData = (sender as SerialPort).ReadLine();
                if (!string.IsNullOrEmpty(recvData))
                {
                    manualResetEventSlim.Set();
                    Mylog.DeviceData(receivedData: recvData, deviceName: deviceName);
                }
            }
        }

        private static void SendCmd(string cmd)
        {
            Mylog.DeviceData(deviceName: deviceName, sendData: cmd);
            serialPort.Write(cmd + StopCode);
        }

        private static string SendCmdAndWaitReturn(string cmd)
        {
            Mylog.DeviceData(deviceName: deviceName, sendData: cmd);
            var sendCmd = cmd + StopCode;
            manualResetEventSlim = new ManualResetEventSlim(false);
            serialPort.Write(sendCmd);
            if (!manualResetEventSlim.Wait(5000))
            {
                throw new Exception("万用表通信异常");
            }
            return recvData;
        }

        /// <summary>
        /// 读取的当前设备状态
        /// </summary>
        /// <returns> </returns>
        public static Function GetFunction()
        {
            string result = SendCmdAndWaitReturn(":FUNCtion?");
            if (result == "2WR")
            {
                result = "WR2";
            }
            else if (result == "4WR")
            {
                result = "WR4";
            }
            if (result != null)
            {
                foreach (Function items in Enum.GetValues(typeof(Function)))
                {
                    if (result == items.ToString())
                    {
                        Function = items;
                        return items;
                    }
                }
            }
            return 0;
        }

        /// <summary>
        /// 设置量程
        /// </summary>
        /// <param name="value"> </param>
        /// <exception cref="Exception"> </exception>
        public static void SetRange(double value)
        {
            if (Function == Function.DIODE) //二极管测试不需要设置量程
            {
                return;
            }
            string cmd = "";
            string cmdHead = SetRangeCmd[Function];
            if (Function == Function.CONT)  //短路测试
            {
                double max = SetRangeParam[Function]["MAX"];
                double min = SetRangeParam[Function]["MIN"];
                if (value > max | value < min)
                {
                    throw new Exception($"{Function.ToString()}参数错误{value}");
                }
                cmd = cmdHead + " " + (int)value;
            }
            else
            {
                bool update = false;
                var param = SetRangeParam[Function];
                foreach (var item in param)
                {
                    if (item.Value >= value)
                    {
                        cmd = cmdHead + " " + item.Key;
                        update = true;
                        break;
                    }
                }
                if (!update)
                {
                    throw new Exception($"{Function.ToString()}错误的量程{value}");
                }
            }
            SendCmd(cmd);
        }

        /// <summary>
        /// 获取量程
        /// </summary>
        /// <returns> </returns>
        public static string GetRange()
        {
            string cmd = SetRangeCmd[Function] + ":RANGe?";
            string result = SendCmdAndWaitReturn(cmd);
            return result;
        }

        /// <summary>
        /// 设置当前万用表功能
        /// </summary>
        /// <param name="func"> </param>
        /// <exception cref="Exception"> </exception>
        public static void SetFunction(Function func)
        {
            string cmd = SetFunctionCmd[func];
            //string cmd = ListSetFunctionCmd.Where(x => x.Key == func).First().Value;
            //string cmd = ListSetFunctionCmd.FirstOrDefault(x => x.Key == func).Value;
            SendCmd(cmd);
            Thread.Sleep(100);
            if (func != GetFunction())
            {
                throw new Exception($"{deviceName} 设置{func}功能异常");
            }
        }

        /// <summary>
        /// function
        /// </summary>
        public static Function Function { get; set; }

        /// <summary>
        /// 获取当前功能状态的值
        /// </summary>
        /// <returns> </returns>
        public static double GetValue()
        {
            //var tmp = GetFunction();
            //if (func != tmp)
            //{
            //    SetFunction(func);
            //}
            //else
            //{
            //    throw new Exception($"{deviceName} 读取{func}功能异常");
            //}
            string cmd = SetRangeCmd[Function] + "?";
            double result = double.Parse(SendCmdAndWaitReturn(cmd));
            return result;
        }
    }
}